package com.sencorsta.ids.core.function;

import com.sencorsta.ids.core.configure.SysConfig;
import com.sencorsta.ids.core.log.Out;
import com.sencorsta.ids.core.tcp.socket.client.RPCLock;
import com.sencorsta.ids.core.tcp.socket.protocol.RpcMessage;
import com.sencorsta.utils.string.StringUtil;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SynFunction {
    private static final int REQUEST_AWAIN = SysConfig.getInstance().getInt("zone.request.await", 15000);
    /**
     * 客户端响应信号通知键生成器
     */
    private static AtomicLong UUID = new AtomicLong(System.currentTimeMillis());
    private static Map<Long, RPCLock> LOCKS = new ConcurrentHashMap<>();

    public static RpcMessage request(RpcMessage req) {
        long reqId = UUID.incrementAndGet();
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            req.msgId = reqId;
            Condition condition = lock.newCondition();
            RPCLock look = new RPCLock(lock, condition);
            LOCKS.put(reqId, look);
            req.channel.writeAndFlush(req);
            condition.await(REQUEST_AWAIN, TimeUnit.MILLISECONDS);
            LOCKS.remove(reqId);
            if (!StringUtil.isEmpty(look.errMsg)||look.message == null) {
                throw new Exception("请求异常");
            }
            return look.message;
        } catch (Exception e) {
            e.printStackTrace();
            Out.error(e);
        } finally {
            lock.unlock();
        }
        return null;
    }

    public static void response(long reqId, RpcMessage res) {
        RPCLock lock = LOCKS.get(reqId);
        if (lock != null) {
            lock.lock.lock();
            try {
                lock.message = res;
                lock.errMsg = res.errMsg;
                lock.condition.signal();
            } catch (Exception e) {
                Out.error(e);
            } finally {
                lock.lock.unlock();
            }
        } else {
            Out.warn(reqId, " request timeout!!!");
        }
    }
}
